package ord2.indexer;

import ord2.core.Parametric;
import ord2.core.Parameter;
import java.util.LinkedList;
import java.io.File;
import java.util.Arrays;
import java.util.List;
/**
 * An abstract indexer that implements parametric operations.
 *
 * @author José Ivan
 * @author Edviges
 *
 */
public abstract class AbstractIndexer implements Indexer, Parametric {
    
    private LinkedList<File> documents = new LinkedList<File>();
    private LinkedList<Parameter> pars = new LinkedList<Parameter>();
    private File indexDir = null;
    private boolean processing = false;
    
    /**
     * Constructs a indexer with parameters that will be used on indexing.
     * @param pars Array of parameters.
     */
    public AbstractIndexer(Parameter[] pars) {
        
        if (pars == null) {
            
            throw new NullPointerException("Parameters cannot be null");
        }
        //Verifice se o parâmetro de caminho do index existe
        for (Parameter p : pars) {
            
            if (p.getName().equals("path")) {
                
                this.setIndexPath(new File(p.getValue()));
                break;
            }
        }
        
        this.pars.addAll(Arrays.asList(pars));        
    }
    
    /**
     * Constructs a indexer without documents and using default parameters.
     */
    public AbstractIndexer() {

        //Nothing to do
    }
    
    /**
     * Construcs a indexer with a colletion of documents and parameters that will
     * be used in indexing;
     * @param docs Colletion of documents
     * @param pars Array of parameters
     */
    public AbstractIndexer(File[] docs, Parameter[] pars) {

        this(pars);
        for (File f : docs) {
            
            if (f.isFile()) {
                
                this.documents.add(f);
            }
        }
    }
    
    /**
     * Gets File that represents directory where index will be created.
     * @return File representing index directory.
     */
    public final File getIndexDir() {
        
        return this.indexDir;
    }
    
    /**
     * Adds a parameter to be used in indexing.
     * @param par Parameter to be added.
     * @throws NullPointerException if par is null
     */
    @Override
    public final void addParameter(Parameter par) {
        
        if (par == null) {
            
            throw new NullPointerException("Parameter cannot be null");
        }
        
        this.pars.add(par);
    }
    
    /**
     * Removes a paramater that is being used in indexing or nothing if it doesn't
     * exist.
     * @param par Parameter that will be removed
     */
    @Override
    public final void removeParameter(Parameter par) {
        
        this.pars.remove(par);
    }
    
    /**
     * Returns all parameters that are being used in indexing.
     * @return Array that contais all parameters.
     */
    @Override
    public final Parameter[] getParameters() {
        
        return this.pars.toArray(new Parameter[0]);
    }
    
    @Override
    public synchronized final boolean addDocument(File doc) {
        
        //Verifica se o documento já existe
        if (this.documents.contains(doc)) {
            
            return false;
        }
        
        this.documents.add(doc);
        return true;
    }
    
    @Override
    public final boolean removeDocument(File doc) {
        
        return this.documents.remove(doc);
    }
    
    @Override
    public final boolean isProcessing() {
        
        synchronized (this) {
            
            return this.processing;
        }
    }
    
    public final File getConfigurationFile() {
        
        return this.indexDir;
    }
    
    public final void setIndexPath(File indexDir) {
        
        this.indexDir = indexDir;
    }
    
    @Override
    public final File[] getAllDocuments() {
        
        return this.documents.toArray(new File[0]);
    }
    
    protected final void notifyStartProcessing() {
        
        synchronized (this) {
        
            this.processing = true;
        }
    }
    
    protected final void notifyStopProcessing() {
        
        synchronized (this) {
            
            this.processing = false;
        }
    }
}
